﻿using RSSReader.Dto;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel.Syndication;

namespace RSSReader
{
    public class ObservableSyndicationItem : NotificationObject, IEquatable<ObservableSyndicationItem>
    {
        private ObservableSyndicationFeed feed;
        private ObservableCollection<string> hiddenAuthors;
        private ReadOnlyObservableCollection<string> authors;
        private Uri baseUri;
        private string id;
        private DateTimeOffset publishDate;
        private DateTimeOffset lastUpdatedTime;
        private string summary;
        private string title;
        private bool isNew;
        private bool isUpdated;
        private bool isRead;

        public ObservableSyndicationItem(ObservableSyndicationFeed feed, SyndicationItem syndicationItem)
        {
            this.feed = feed;
            this.hiddenAuthors = new ObservableCollection<string>(syndicationItem.Authors.Select(author => author.Name));
            this.authors = new ReadOnlyObservableCollection<string>(hiddenAuthors);
            this.baseUri = syndicationItem.BaseUri;
            this.id = syndicationItem.Id;
            this.publishDate = syndicationItem.PublishDate;
            this.lastUpdatedTime = syndicationItem.LastUpdatedTime;
            if (syndicationItem.Summary != null)
            {
                this.summary = this.RemoveHTML(syndicationItem.Summary.Text);
            }
            else
            {
                this.summary = string.Empty;
            }
            if (syndicationItem.Title != null)
            {
                this.title = syndicationItem.Title.Text;
            }
            else
            {
                this.title = string.Empty;
            }
            this.isNew = true;
            this.isUpdated = false;
            this.isRead = false;
        }

        public ObservableSyndicationItem(ObservableSyndicationFeed feed, ObservableSyndicationItemDto itemDto)
        {
            this.feed = feed;
            this.hiddenAuthors = new ObservableCollection<string>(itemDto.Authors);
            this.authors = new ReadOnlyObservableCollection<string>(hiddenAuthors);
            this.baseUri = itemDto.BaseUri;
            this.id = itemDto.Id;
            this.publishDate = itemDto.PublishDate;
            this.lastUpdatedTime = itemDto.LastUpdatedTime;
            this.summary = itemDto.Summary ?? string.Empty;
            this.title = itemDto.Title ?? string.Empty;
            this.isNew = itemDto.IsNew;
            this.isUpdated = itemDto.IsUpdated;
            this.isRead = itemDto.IsRead;
        }

        public ObservableSyndicationFeed Feed
        {
            get
            {
                return this.feed;
            }
        }

        public ReadOnlyObservableCollection<string> Authors
        {
            get
            {
                return this.authors;
            }
        }

        public Uri BaseUri
        {
            get
            {
                return this.baseUri;
            }
            set
            {
                if (this.baseUri != value)
                {
                    this.baseUri = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public string Id
        {
            get
            {
                return this.id;
            }
            set
            {
                if (this.id != value)
                {
                    this.id = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public DateTimeOffset PublishDate
        {
            get
            {
                return this.publishDate;
            }
            set
            {
                if (this.publishDate != value)
                {
                    this.publishDate = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public DateTimeOffset LastUpdatedTime
        {
            get
            {
                return this.lastUpdatedTime;
            }
            set
            {
                if (this.lastUpdatedTime != value)
                {
                    this.lastUpdatedTime = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public string Summary
        {
            get
            {
                return this.summary;
            }
            set
            {
                if (this.summary != value)
                {
                    this.summary = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if (this.title != value)
                {
                    this.title = value;
                    this.OnPropertyChanged();
                }
            }
        }

        public bool IsNew
        {
            get
            {
                return this.isNew;
            }
        }

        public bool IsUpdated
        {
            get
            {
                return this.isUpdated;
            }
        }

        public bool IsRead
        {
            get
            {
                return this.isRead;
            }
        }

        private string RemoveHTML(string text)
        {
            if (text == null)
            {
                return string.Empty;
            }

            if (text.Contains('<'))
            {
                return text.Remove(text.IndexOf('<'));
            }

            return text;
        }

        public void ShowItemInBrowser()
        {
            if (this.Id == null)
            {
                throw new Exception("Item has no URL");
            }

            if (!Uri.IsWellFormedUriString(this.Id, UriKind.Absolute))
            {
                throw new Exception("Item has no valid URL");
            }

            Process.Start(this.Id);
        }

        /// <summary>
        /// Markiert das Item als gelesen
        /// </summary>
        public void MarkRead()
        {
            this.isRead = true;
            this.OnPropertyChanged("IsRead");
        }

        /// <summary>
        /// Markiert das Item als alt
        /// </summary>
        public void MarkOld()
        {
            this.isNew = false;
            this.OnPropertyChanged("IsNew");
        }

        public void Update(SyndicationItem updatedSyndicationItem)
        {
            //Item must have the same id as the present item
            if (this.Id != updatedSyndicationItem.Id)
                return;

            //Item must be newer then the item present
            if (this.LastUpdatedTime == updatedSyndicationItem.LastUpdatedTime)
                return;

            if (!this.hiddenAuthors.SequenceEqual(updatedSyndicationItem.Authors.Select(author => author.Name)))
            {
                this.hiddenAuthors.Clear();
                foreach (var author in updatedSyndicationItem.Authors)
                {
                    this.hiddenAuthors.Add(author.Name);
                }
            }
            this.BaseUri = updatedSyndicationItem.BaseUri;
            this.Id = updatedSyndicationItem.Id;
            this.PublishDate = updatedSyndicationItem.PublishDate;
            this.LastUpdatedTime = updatedSyndicationItem.LastUpdatedTime;
            this.Summary = this.RemoveHTML(updatedSyndicationItem.Summary.Text);
            this.Title = updatedSyndicationItem.Title.Text;

            this.isUpdated = true;
            this.OnPropertyChanged("IsUpdated");

            this.isRead = false;
            this.OnPropertyChanged("IsRead");
        }

        public bool Equals(ObservableSyndicationItem other)
        {
            if (this.Authors != other.Authors)
                return false;

            if (this.BaseUri != other.BaseUri)
                return false;

            if (this.Id != other.Id)
                return false;

            if (this.LastUpdatedTime != other.LastUpdatedTime)
                return false;

            if (this.PublishDate != other.PublishDate)
                return false;

            if (this.Summary != other.Summary)
                return false;

            if (this.Title != other.Title)
                return false;

            return true;
        }

        public ObservableSyndicationItemDto GetDto()
        {
            var itemDto = new ObservableSyndicationItemDto();

            itemDto.Authors = new List<string>(this.authors);
            itemDto.BaseUri = this.baseUri;
            itemDto.Id = this.id;
            itemDto.IsNew = this.isNew;
            itemDto.IsUpdated = this.isUpdated;
            itemDto.IsRead = this.isRead;
            itemDto.LastUpdatedTime = this.lastUpdatedTime;
            itemDto.PublishDate = this.publishDate;
            if (this.summary != null)
                itemDto.Summary = this.summary;
            if (this.title != null)
                itemDto.Title = this.title;

            return itemDto;
        }
    }
}
